
//////// I N C L U D E S ////////////////////////////////////////////

// Main header
#include "Main.h"

// My header
#include "TextureManager.h"

// Fridge headers
#include "StringHash.h"
#include "SimplePNG.h"
#include "TypedList.h"

// External
#include <stdio.h>

//////// C O N S T A N T S //////////////////////////////////////////


//////// C L A S S   D E C L A R A T I O N S ////////////////////////

class Texture
{
	public:

		Texture()
		{
			xHash = INVALID_STRING_HASH;
		}

		StringHash	xHash;
		SimplePNG	xPNGData;
};

//////// F U N C T I O N   D E F I N I T I O N S ////////////////////

TextureManager::TextureManager()
{
	m_pxTextureList = new TypedList< Texture >( true );
	m_puGLTextureIDs = 0;
}

TextureManager::~TextureManager()
{
	Clear();
}

void TextureManager::LoadFromTextureListFile( const char* szTextureListFileName )
{
	// Open the texture list and read it in
	// TODO: If there are a lot of textures to load it might be worth threading this out
	const u_int uMaxString = 256;

	char szFilename[uMaxString];
	char szRefname[uMaxString];

	FILE* pxFile = 0;
	
	pxFile = fopen( szTextureListFileName, "rt" );

	if( pxFile )
	{
		u_int uChar = 0;

		while( !feof( pxFile ) )
		{
			memset( szFilename, 0, sizeof( char ) * uMaxString );
			memset( szRefname, 0, sizeof( char ) * uMaxString );

			// Read the reference name
			uChar = 0;
			while( ( ( szRefname[uChar] = static_cast<char>( fgetc( pxFile ) ) ) != '|' ) && !feof( pxFile ) )
			{
				if( ( szRefname[uChar] == '#' ) && ( uChar == 0 ) )
				{
					// If the first char of a line is # we skip the line
					while( static_cast<char>( fgetc( pxFile ) ) != '\n' ) {}

					continue;
				}

				++uChar;
				if( uChar == ( uMaxString - 1 ) )
				{
					break;
				}
			}
			szRefname[ uChar ] = 0;

			// Read the file name
			uChar = 0;
			while( !feof( pxFile ) )
			{
				szFilename[uChar] = static_cast<char>( fgetc( pxFile ) );
				if( szFilename[uChar] == '\n' || uChar == ( uMaxString - 1 ) )
				{
					break;
				}
				if( szFilename[uChar] == '\r' )
				{
					/* Catch OSX line endings should the file ever be saved that way*/
					int iPeekChar = fgetc( pxFile );
					if( iPeekChar != '\n' )
					{
						ungetc( iPeekChar, pxFile );
					}
					break;
				}
				
				/* Sieve out any other nonprintable character. This catches -1,
				   which happens once before feof() becomes true. */
				if( szFilename[uChar] < ' ' )
				{
					continue;
				}
				++uChar;
			}
			szFilename[ uChar ] = 0;

			// Create a texture
			if( szFilename[0] && szRefname[0] )
			{
				Texture* pxTexture = new Texture;
				
				if( pxTexture->xPNGData.LoadFromFile( szFilename ) )
				{
					pxTexture->xHash = GetStringHash( szRefname );
					m_pxTextureList->Add( pxTexture );
				}
				else
				{
					// Failed to load
					FridgeLogf("Texture Manager: Failed to load texture %s\n", szFilename);
					
					FridgeLog("Filename: ");
					for( int i=0; i< (int)strlen(szFilename); i++)
					{
						FridgeLogf("|%c=",szFilename[i]);
						FridgeLogf("%x",szFilename[i]);
					}
					FridgeLog("\n");
					
					delete pxTexture;
				}
			}
		}

		fclose( pxFile );
	}

	// Generate OpenGL textures
	glEnable( GL_TEXTURE_2D );

	m_puGLTextureIDs = new GLuint[ m_pxTextureList->Count() ];

	glGenTextures( m_pxTextureList->Count(), m_puGLTextureIDs );

	for( u_int uItem = 0; uItem < m_pxTextureList->Count(); ++uItem )
	{
		Texture* pxTexture = m_pxTextureList->Get( uItem );

		if( !pxTexture ) 
		{
			continue;
		}

		glBindTexture( GL_TEXTURE_2D, m_puGLTextureIDs[ uItem ] );

		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR );


		glTexImage2D(	GL_TEXTURE_2D,
						0,
						GL_RGBA8, 
						pxTexture->xPNGData.GetWidth(),
						pxTexture->xPNGData.GetHeight(),
						0,
						GL_RGBA,
						GL_UNSIGNED_BYTE,
						pxTexture->xPNGData.GetImageData() );
	}

	glDisable( GL_TEXTURE_2D );

}


void TextureManager::Update ()
{

}


void TextureManager::Clear ()
{
	glDeleteTextures( m_pxTextureList->Count(), m_puGLTextureIDs );

	delete []m_puGLTextureIDs;
	m_puGLTextureIDs = NULL;

	delete m_pxTextureList;
	m_pxTextureList = NULL;
}

int TextureManager::GetTextureID(const StringHash& xHash)
{
	for( u_int uItem = 0; uItem < m_pxTextureList->Count(); ++uItem )
	{
		Texture* pxTexture = m_pxTextureList->Get( uItem );
		if( pxTexture->xHash == xHash )
		{
			return m_puGLTextureIDs[ uItem ];
		}
	}

	return INVALID_TEXTURE_ID;
}

//eof
